from django.db import models
import requests
import user_agents
import csv
import hashlib
import datetime
import os
from .my_cache import lru_cache
from django.core.cache import cache

# 请求记录表


class RequestRecord(models.Model):
    path = models.CharField(max_length=100, default='/',
                            db_column='请求路径', verbose_name='请求路径', help_text='请求路径')
    method = models.CharField(max_length=100, default='GET',
                              db_column='请求方式', verbose_name='请求方式', help_text='请求方式')
    ip = models.CharField(max_length=50, db_column='IP地址',
                          verbose_name='IP地址', help_text='IP地址')
    user_agent = models.CharField(
        max_length=500, db_column='请求头', verbose_name='请求头', help_text='请求头')
    http_refer = models.URLField(
        default='', db_column='跳转的网页', verbose_name='跳转的网页', help_text='跳转的网页')
    os = models.CharField(default='', max_length=100, db_column='操作系统',
                          verbose_name='操作系统', help_text='操作系统')
    country = models.CharField(
        max_length=50, default='', db_column='国家', verbose_name='国家', help_text='国家')
    province = models.CharField(
        max_length=50, default='', db_column='省份', verbose_name='省份', help_text='省份')
    city = models.CharField(max_length=50, default='',
                            db_column='城市', verbose_name='城市', help_text='城市')
    time = models.DateTimeField(
        auto_now=True, db_column='时间', verbose_name='时间', help_text='时间')

    class Meta:
        db_table = '请求记录'
        verbose_name = verbose_name_plural = db_table

    @classmethod
    def get_all(cls):
        return cls.objects.all()

    # 获取某天或某月或某年的访问量
    @classmethod
    @lru_cache(size=128, expires_check=True, expires=60*60)
    def get_views(cls, year=None, moth=None, day=None):
        request_li = cls.objects
        if year:
            request_li = request_li.filter(time__year=year)
        if moth:
            request_li = request_li.filter(time__month=moth)
        if day:
            request_li = request_li.filter(time__day=day)
        ip_li = request_li.values_list('ip').distinct()
        return ip_li.count()

    # 获取ip地址
    @classmethod
    def get_address(cls, ip):
        api_url = f'https://freeapi.ipip.net/{ip}'
        try:
            # 先从缓存中获取，如果没有就再请求接口
            location = cache.get(ip, None)
            if not location:
                res = requests.get(api_url)
                location = res.json()[:3]
                cache.set(ip, location, 60*60*24*7)  # 假设一个用户7天之内不会更换位置
            return location
        except Exception as e:
            return ['', '', '']

    # 新建一个请求记录
    @classmethod
    def create_request_record(cls, path, method, ip, user_agent, http_refer, os, country, province, city):
        requestLog = cls()
        requestLog.path = path
        requestLog.method = method
        requestLog.ip = ip
        requestLog.user_agent = user_agent
        requestLog.http_refer = http_refer
        requestLog.os = os
        requestLog.country = country
        requestLog.province = province
        requestLog.city = city
        # requestLog.save()
        return requestLog

    # 统计ip数据
    @classmethod
    @lru_cache(size=128, expires_check=True, expires=60*60)
    def stat_ip(cls, country, province, city, start_time, end_time):
        '''
        data = {
            '中国': {
                '湖北': {
                    '武汉': {
                        'count': 10, #总次数
                        'ip_dict': {
                            '127.0.0.1': 1, #每个ip的访问次数
                            '127.0.0.3': 2,
                        },

                    }
                },
            },
            '美国': {},
        }
        '''
        record_list = cls.objects.filter(time__range=(start_time, end_time))
        if country:
            record_list = record_list.filter(country=country)
        if province:
            record_list = record_list.filter(province=province)
        if city:
            record_list = record_list.filter(city=city)
        record_list = record_list.all()

        data = {}
        data_list = []
        for record in record_list:
            data_country = data.get(record.country, {})  # 国家
            data_country_province = data_country.get(record.province, {})
            data_country_province_city = data_country_province.get(
                record.city, {})
            count = data_country_province_city.get('count', 0)
            ip_dict = data_country_province_city.get('ip_dict', {})
            ip_count = ip_dict.get(record.ip, 0)
            ip_dict[record.ip] = ip_count + 1

            data_country_province_city['count'] = count + 1
            data_country_province_city['ip_dict'] = ip_dict

            data_country_province[record.city] = data_country_province_city
            data_country[record.province] = data_country_province
            data[record.country] = data_country

            data_list.append({
                'country': record.country,
                'province': record.province,
                'city': record.city,
                'ip': record.ip,
                'time': record.time
            })
        data_path = cls.write_file(data_list)
        return (data, data_path)

    # 统计浏览器数据
    @classmethod
    @lru_cache(size=128, expires_check=True, expires=60*60)
    def stat_browser(cls, start_time, end_time):

        data = {}
        data_list = []
        record_list = cls.objects.filter(
            time__range=(start_time, end_time)).all()
        for reocrd in record_list:
            res = user_agents.parse(reocrd.user_agent)
            brower_name = res.browser.family
            browser_version = res.browser.version_string
            browser = data.get(brower_name, {})
            times = browser.get(browser_version, 0)
            browser[browser_version] = times+1
            data[brower_name] = browser
            data_list.append({
                'brower': brower_name,
                'version': browser_version,
                'os': reocrd.os,
                'time': reocrd.time,
                'user-agent': reocrd.user_agent,
            })
        data_path = cls.write_file(data_list)
        return (data, data_path)

    # 将数据写入文件
    @staticmethod
    def write_file(data_lsit):
        file_name = hashlib.sha256(
            bytes(str(data_lsit), encoding='utf8')).hexdigest()
        now = datetime.datetime.now()
        year, month, day = now.year, now.month, now.day
        _dir = os.path.join('media', 'files', str(year), str(month), str(day))
        if not os.path.isdir(_dir):
            os.makedirs(_dir)
        path = os.path.join(_dir, f'{file_name}.csv')
        fieldnames = data_lsit[0].keys() if data_lsit else []
        with open(path, 'w', encoding='utf8', newline='') as f:
            writer = csv.DictWriter(f, fieldnames)
            writer.writeheader()
            for row in data_lsit:
                writer.writerow(row)

        return path
